/***********************************************************
 * Product Name: ExcelQuicker
 * Copyright (c)2005, Eunge
 * Author: Eunge
 * Web Site: www.eudev.net
 * Mail/MSN: eudev.net@yeah.net
 * ********************************************************/
using System;
using System.IO;
using System.Web;
using System.Collections;
using System.Xml;

namespace ExcelQuicker.Framework
{
	/// <summary>
	/// Web Kit. Provides several usual functions when developing web application
	/// </summary>
	public sealed class EQWebKit
	{
		private EQWebKit(){}

		/// <summary>
		/// Download Excel format report to client
		/// </summary>
		/// <param name="fileName">Physical file name</param>
		public static void DownloadExcelReport(string fileName)
		{
			HttpResponse response = HttpContext.Current.Response;
			string strJs = "<script language=javascript>window.open('{0}');</script>";
			strJs = string.Format(strJs, EQWebKit.GetRelativeFileName(fileName));
			response.Write(strJs);
		}


		/// <summary>
		/// Download HTML format report to client
		/// </summary>
		/// <param name="fileName">Physical file name</param>
		public static void ShowHTMLReport(string fileName)
		{
			HttpResponse response = HttpContext.Current.Response;
			string strRelativePath = EQWebKit.GetRelativeFileName(fileName);
			EQWebKit.OpenIEWindow(strRelativePath);
		}


		/// <summary>
		/// </summary>
		/// <param name="fileName">Absolute/relative file name</param>
		/// <remarks>The function will output a window.open(...) call with the parameters as "alwaysRaised=yes,depended =yes,location=no,resizable =no,toolbar=yes,menubar =yes,width=720,height=520,scrollbars=yes,status=no,titlebar=no"</remarks>
		public static void OpenIEWindow(string fileName)
		{
			HttpResponse response = HttpContext.Current.Response;
			string strParam = "alwaysRaised=yes,depended =yes,location=no,resizable=yes,toolbar=yes,menubar =yes,width=720,height=520,scrollbars=yes,status=no,titlebar=no";
			string strJs = "<script language=javascript>window.open('{0}','ExcelQuickerHtmlReport','{1}');</script>";
			strJs = string.Format(strJs, fileName, strParam);
			response.Write(strJs);
		}


		/// <summary>
		/// Convert physical file name to relative based on the current request uri(HttpContext.Current.Uri). The precondition of this call is that the file name must be in the current application virtual path
		/// </summary>
		/// <param name="fileName"></param>
		/// <returns></returns>
        public static string GetRelativeFileName(string fileName)
        {
            string strRequestPage = Path.GetDirectoryName(HttpContext.Current.Request.Url.AbsoluteUri.ToLower()); //Get request uri
            string strApplicationName = HttpRuntime.AppDomainAppVirtualPath.ToLower().Replace("/", "").Replace("\\", "");	//Get application name
            int pos = strRequestPage.IndexOf(strApplicationName);
            strRequestPage = strRequestPage.Substring(pos);
            int iLevel = 0;	//The level of request page to application virtual path
            string strParentPath = strRequestPage;
            while (strParentPath != strApplicationName && iLevel < 100)	//If iLevel reach 100, I think may be there is same problem of this arithmetic
            {
                iLevel++;
                strParentPath = Directory.GetParent(strRequestPage).Name;
            }
            string strFileName = fileName.ToLower();	//The report file name
            // NOTICE: make sure AppName == DirName, and after that, there is no reduplicate name
            // Example: if AppName == "MyApp" then:
            // valid (webroot folder, webpath, tempreports pathname):
            // ("C:\inetpub\wwwroot\MyApp\",  "http://localhost/MyApp/", "C:\inetpub\wwwroot\MyApp\TempReports\MyExcel.xls")
            // ("D:\MyApp\",                  "http://localhost/MyApp/", "D:\MyApp\TempReports\MyExcel.xls")
            // ("D:\MyAppRoot\MyApp\",        "http://localhost/MyApp/", "D:\MyAppRoot\MyApp\TempReports\MyExcel.xls")
            // invalid (webroot folder, tempreports pathname):
            // ("C:\inetpub\wwwroot\MyApp\",  "http://localhost/MyApp/", "C:\inetpub\wwwroot\MyApp\TempReports\MyAppExcel.xls")
            // ("C:\inetpub\wwwroot\MyApp\",  "http://localhost/",       "C:\inetpub\wwwroot\MyApp\TempReports\MyExcel.xls")
            // ("D:\MyApp\",                  "http://localhost/MyApp/", "D:\MyApp\MyAppExcel\TempReport\MyExcel.xls")
            pos = strFileName.LastIndexOf(strApplicationName);
            strFileName = strFileName.Substring(pos + strApplicationName.Length + 1);
            string strRelativePath = string.Empty;	//The relative path of report file to the current request uri
            while (iLevel-- > 0)
                strRelativePath += "..\\";
            strRelativePath += strFileName;
            strRelativePath = strRelativePath.Replace("\\", "/");
            return strRelativePath;
        }

        #region Debug version GetRelativeFileName

        /*
        public static string GetRelativeFileName(string fileName)
        {
            string strRelativePath = string.Empty;	//The relative path of report file to the current request uri

            StreamWriter writer = new StreamWriter(HttpContext.Current.Request.PhysicalApplicationPath + "/Debug/EQWebKit.cs_GetRelativeFileName.log", true);
            try
            {
                writer.WriteLine(DateTime.Now.ToString("u") + " --------------------------- ");
                writer.WriteLine(DateTime.Now.ToString("u") + " Enter GetRelativeFileName(fileName = \"{0}\"", fileName);

                string strRequestPage = Path.GetDirectoryName(HttpContext.Current.Request.Url.AbsoluteUri.ToLower()); //Get request uri

                writer.WriteLine(DateTime.Now.ToString("u") + " strRequestPage = \"{0}\"", strRequestPage);

                string strApplicationName = HttpRuntime.AppDomainAppVirtualPath.ToLower().Replace("/", "").Replace("\\", "");	//Get application name

                writer.WriteLine(DateTime.Now.ToString("u") + " strApplicationName(Rough) = \"{0}\"", strApplicationName);

                int pos = strRequestPage.IndexOf(strApplicationName);

                writer.WriteLine(DateTime.Now.ToString("u") + " strRequestPage.IndexOf(strApplicationName) = \"{0}\"", pos);

                strRequestPage = strRequestPage.Substring(pos);
                int iLevel = 0;	//The level of request page to application virtual path
                string strParentPath = strRequestPage;
                while (strParentPath != strApplicationName && iLevel < 100)	//If iLevel reach 100, I think may be there is same problem of this arithmetic
                {
                    iLevel++;
                    strParentPath = Directory.GetParent(strRequestPage).Name;
                }

                writer.WriteLine(DateTime.Now.ToString("u") + " strParentPath(strApplicationName) = \"{0}\"", strParentPath);
                writer.WriteLine(DateTime.Now.ToString("u") + " iLevel = \"{0}\"", iLevel);

                string strFileName = fileName.ToLower();	//The report file name
                pos = strFileName.LastIndexOf(strApplicationName);

                writer.WriteLine(DateTime.Now.ToString("u") + " fileName.IndexOf(strApplicationName) = \"{0}\"", pos);

                strFileName = strFileName.Substring(pos + strApplicationName.Length + 1);

                writer.WriteLine(DateTime.Now.ToString("u") + " strFileName = strFileName.Substring(pos + strApplicationName.Length + 1);");
                writer.WriteLine(DateTime.Now.ToString("u") + " strFileName = \"{0}\"", strFileName);

                while (iLevel-- > 0)
                    strRelativePath += "..\\";
                strRelativePath += strFileName;
                strRelativePath = strRelativePath.Replace("\\", "/");

                writer.WriteLine(DateTime.Now.ToString("u") + " strRelativePath = \"{0}\"", strRelativePath);
                // return strRelativePath;

            }
            catch (Exception ex)
            {
                if (null != writer) writer.WriteLine("Exception : {0},{1}", ex.Message, ex.Source);

            }
            finally
            {
                if (null != writer) writer.Close();
            }
            return strRelativePath;

        }
        */
        #endregion 

        /// <summary>
		/// Get inside HTML code using iframe tag. We can set these HTML code into a html controls and display them on the web page
		/// </summary>
		/// <param name="fileName"></param>
		/// <returns></returns>
		public static string GetInsideHtmlReport(string fileName)
		{
			string strIFrame = "<iframe runat=\"server\" style=\"width:100%;height:100%;\" src=\"{0}\"></iframe>";
			strIFrame = string.Format(strIFrame, EQWebKit.GetRelativeFileName(fileName));
			return strIFrame;
		}

		/// <summary>
		/// Automatical generated *.xls file name without path name.
		/// </summary>
		/// <example>Generate a file name likes xzasdq-asdasd-asda-sdasda.xls</example>
		/// <returns></returns>
		public static string GenerateAutoFileName()
		{
			return EQWebKit.GenerateAutoFileName(".xls");
		}


		/// <summary>
		/// Automatical generate a file name with subfix param extension name buy without path name.
		/// </summary>
		/// <param name="extension">Extension name</param>
		/// <returns></returns>
		/// <example>
		/// EQWebKit.GetAutoGenerateFileName(".htm") will return a file name likes xzasdq-asdasd-asda-sdasda.htm
		/// </example>
		public static string GenerateAutoFileName(string extension)
		{
			string strFileName = Guid.NewGuid().ToString() + extension;	//Generated file name as a GUID NO.
			return strFileName;
		}


		/// <summary>
		/// Automatical generated *.xls file name under the specialized path
		/// </summary>
		/// <param name="path">The generated file will under this path</param>
		/// <returns></returns>
		public static string GenerateAutoFullFileName(string path)
		{
			return EQWebKit.GenerateAutoFullFileName(path, ".xls");
		}


		/// <summary>
		/// Automatical generated file name under the specialized path
		/// </summary>
		/// <param name="path">The generated file will under this path</param>
		/// <param name="extension">Extension name, ext .xls, .txt and so on</param>
		/// <returns></returns>
		public static string GenerateAutoFullFileName(string path, string extension)
		{
			if(!Directory.Exists(path))
				throw new EQException("EQ1035", path);
			string strFileName = "";
			strFileName = Guid.NewGuid().ToString() + extension;	//Generated file name as a GUID NO.
			char last = path[path.Length-1];
			if(last=='\\' || last =='/')
				return path + strFileName;
			else 
				return path + "\\" + strFileName;
		}


		/// <summary>
		/// Read the text of a special file, and return its text as string type variable
		/// </summary>
		/// <param name="fileName"></param>
		/// <returns></returns>
		public static string ReadTextFile(string fileName)
		{
			if(!File.Exists(fileName))
				throw new EQException("EQ1026", new string[]{fileName});
			StreamReader sr = null;
			string strHtml = string.Empty;
			try
			{
				sr = new StreamReader(fileName);
				strHtml = sr.ReadToEnd();
			}
			finally
			{
				sr.Close();
			}
			return strHtml;
		}

		/// <summary>
		/// Look up whether the file with file name as parameter in the current application project directory. If it is, return true.
		/// </summary>
		/// <param name="fileName"></param>
		/// <returns></returns>
		public static bool LookupFiles(string fileName)
		{
			string[] files;
			return EQWebKit.LookupFiles(fileName, out files);
		}

		/// <summary>
		/// Look up whether the file with file name as parameter in the current application project directory.
		/// Return there file names as a list in out parameter files.
		/// </summary>
		/// <param name="fileName"></param>
		/// <param name="files">Return list of files' name </param>
		/// <returns></returns>
		public static bool LookupFiles(string fileName, out string[] files)
		{
			ArrayList arraylistFiles = new ArrayList();
			IterateDirectory(fileName, arraylistFiles);
			if(arraylistFiles.Count > 0)
			{
				files = new string[arraylistFiles.Count];
				int index = 0;
				IEnumerator ie = arraylistFiles.GetEnumerator();
				while(ie.MoveNext())
					files[index ++] = ie.Current.ToString();
				return true;
			}
			else 
			{
				files = null;
				return false;
			}
		}

		#region Method LookupFiles Relative
		private static void IterateDirectory(string fileName, ArrayList arraylistFiles)
		{
			DirectoryInfo di = new DirectoryInfo(HttpRuntime.AppDomainAppPath);
			IterateDirectory(fileName, di, arraylistFiles);
		}

		private static void IterateDirectory(string fileName, DirectoryInfo di, ArrayList arraylistFiles)
		{
			string strFileName = (di.FullName[di.FullName.Length - 1]=='\\' || di.FullName[di.FullName.Length - 1] == '/')? di.FullName+ fileName: di.FullName + "\\" + fileName;
			if(File.Exists(strFileName))
				arraylistFiles.Add(strFileName);

			DirectoryInfo[] dis = di.GetDirectories();
			foreach(DirectoryInfo subdi in dis)
				IterateDirectory(fileName, subdi, arraylistFiles);
		}
		#endregion

		/// <summary>
		/// Convert HTML report and expand it's width to 100%.
		/// </summary>
		/// <param name="fileName"></param>
		public static void ConvertHTMLReport(string fileName)
		{
			if(!File.Exists(fileName))
				throw new EQException("EQ1042", fileName);
			string strExt = Path.GetExtension(fileName).ToLower();
			if(strExt != ".htm"&& strExt != ".html")
				throw new EQException("EQ1043", strExt);

			StreamReader sr = new StreamReader(fileName);
			string strText = sr.ReadToEnd();
			sr.Close();

			int startPos = strText.IndexOf("<table x:str ");
			int endPos = strText.IndexOf(">", startPos);
			string strSub = strText.Substring(startPos, endPos - startPos + 1);

			int posWidth0 = strSub.IndexOf("width=") + 6;
			int posWidth1 = strSub.IndexOf(" ", posWidth0);
			string strNewSub = strSub.Substring(0, posWidth0);
			strNewSub += "100%";
			strNewSub += strSub.Substring(posWidth1);
			string strResult = strNewSub;

			posWidth0 = strNewSub.IndexOf("width:");
			if(posWidth0 != -1)
			{
				startPos = strNewSub.IndexOf("'", posWidth0 + 6);
				if(startPos == -1)
					startPos = int.MaxValue;
				endPos = strNewSub.IndexOf(";", posWidth0 + 6);
				if(endPos == -1)
					endPos = int.MaxValue;
				posWidth1 = startPos< endPos? startPos: endPos;
				strResult = strNewSub.Substring(0, posWidth0);
				strResult += strNewSub.Substring(posWidth1);
			}

			strText = strText.Replace(strSub, strResult);

			StreamWriter sw = new StreamWriter(fileName, false);
			sw.Write(strText);
			sw.Close();
		}
	}
}